#include "QPropertySet.h"
using namespace QPE;

#include "private/QPropertySet_p.h"


QPropertySet::QPropertySet()
	: d_ptr(new QPropertySetPrivate())
{
}


QPropertySet::~QPropertySet()
{
	// Delete all the properties
	clear(true);

	delete d_ptr;
}

bool QPropertySet::addProperty(QProperty *property, const QString &id, const QString &parentid)
{
	// Check if the property to add is not a null pointer
	if(!property)
		return false;

	QProperty* tmpParent = parentid.isEmpty() ? NULL : getProperty(parentid);
	return addProperty(property, id, tmpParent);
}

bool QPropertySet::addProperty(QProperty *property, const QString &id, QProperty *parent_property)
{
	// Check if the property to add is not a null pointer
	if(!property)
		return false;

	QString tmpOldID = getPropertyID(property);
	if(!tmpOldID.isEmpty())
		d_ptr->Properties.remove(tmpOldID);

	if(parent_property)
		parent_property->addChild(property);
	else {
		d_ptr->RootProperties.append(property);
		if(property->getParent())
			property->getParent()->removeChild(property);
	}

	if(!id.isEmpty())
		d_ptr->Properties.insert(id, property);

	return true;
}

bool QPropertySet::hasProperty(QProperty *property) const
{
	if(!property)
		return false;

	return hasProperty(property, NULL);
}

QProperty *QPropertySet::getProperty(const QString &id) const
{
	return d_ptr->Properties.value(id, NULL);
}

QProperty *QPropertySet::takeProperty(const QString &id)
{
	QProperty* tmpProp = getProperty(id);
	removeProperty(tmpProp, false);

	// Return the property
	return tmpProp;
}

void QPropertySet::removeProperty(const QString &id)
{
	QProperty* tmpProp = takeProperty(id);
	if(tmpProp)
		delete tmpProp;
}

void QPropertySet::removeProperty(QProperty* prop, bool delete_property)
{
	// Remove all the children
	removePropertyFromSet(prop);

	// Remove from parent and optionally delete
	if(prop) {
		prop->setParent(NULL);

		if(delete_property)
			delete prop;
	}
}

int QPropertySet::count() const
{
	return d_ptr->Properties.count();
}

void QPropertySet::clear(bool delete_properties)
{
	d_ptr->Properties.clear();
	while(!d_ptr->RootProperties.isEmpty()) {
		QProperty* tmpProp = d_ptr->RootProperties.takeLast();
		if(tmpProp != NULL && delete_properties) {
			delete tmpProp;
		}
	}
}

QString QPropertySet::getPropertyID(const QProperty *prop, bool look_for_parent_id) const
{
	QString tmpResult;
	const QProperty* tmpCurrentProp = prop;

	while(tmpCurrentProp && (look_for_parent_id || prop == tmpCurrentProp) && tmpResult.isEmpty()) {

		// todo: The following code doesn't work, because .key() doesn't accept a const QProperty* pointer ...
		//tmpResult = d_ptr->Properties.key(tmpCurrentProp, QString());

		// ... which is why we need the code below
		for (QMap<QString, QProperty*>::const_iterator i = d_ptr->Properties.constBegin(); i != d_ptr->Properties.constEnd(); ++i) {
			if(tmpCurrentProp == (*i))
				return i.key();
		}

		tmpCurrentProp = tmpCurrentProp->getParent();
	}

	return tmpResult;
}

const QMap<QString, QProperty *> &QPropertySet::getPropertiesMap() const
{
	return d_ptr->Properties;
}

const QList<QProperty *> &QPropertySet::getRootProperties() const
{
	return d_ptr->RootProperties;
}

QProperty *QPropertySet::getRootProperty(int row) const
{
	return d_ptr->RootProperties.value(row, NULL);
}

int QPropertySet::getRootPropertyCount() const
{
	return d_ptr->RootProperties.count();
}

QPropertySet* QPropertySet::clone() const
{
	QPropertySet* tmpResult = new QPropertySet();

	foreach(QProperty* tmpProperty, d_ptr->RootProperties)
		cloneProperty(tmpProperty, NULL, tmpResult);


	return tmpResult;
}



bool QPropertySet::hasProperty(QProperty *property, QProperty *parent) const
{
	if(!property)
		return false;

	const QList<QProperty*>& tmpChildrenList = (parent != NULL ? parent->getChildren() : d_ptr->RootProperties);
	foreach(QProperty* tmpProp, tmpChildrenList) {
		if(!tmpProp)
			continue;
		else if(tmpProp == property || hasProperty(property, tmpProp))
			return true;
	}

	return false;
}

void QPropertySet::cloneProperty(QProperty* property_to_clone, QProperty *parent_property, QPropertySet *output_set) const
{
	if(!output_set || !property_to_clone || !hasProperty(property_to_clone))
		return;

	QString tmpID = getPropertyID(property_to_clone, false);
	QProperty* tmpNewProperty = property_to_clone->clone(false);	// We want to clone the children ourselves (because of the IDs)

	output_set->addProperty(tmpNewProperty, tmpID, parent_property);
	for(int i = 0; i < property_to_clone->getRowCount(); ++i)
		cloneProperty(property_to_clone->getChild(i), tmpNewProperty, output_set);
}

void QPropertySet::removePropertyFromSet(QProperty *prop)
{
	// Remove all the children
	foreach(QProperty* tmpChild, prop->getChildren())
		removeProperty(tmpChild);


	QList<QString> tmpKeys = d_ptr->Properties.keys(prop);
	foreach(const QString& tmpID, tmpKeys)
		d_ptr->Properties.remove(tmpID);

	// Remove from list
	d_ptr->RootProperties.removeAll(prop);
}
